home *** CD-ROM | disk | FTP | other *** search
- /*
- * rttinlin.c contains routines which produce the in-line version of an
- * operation and put it in the data base.
- */
- #include "rtt.h"
-
- /*
- * prototypes for static functions.
- */
- hidden int body_anlz Params((struct node *n, int *does_break,
- int may_mod));
- hidden struct il_code *body_fnc Params((struct node *n));
- hidden novalue chkrettyp Params((struct node *n));
- hidden novalue chng_ploc Params((struct node *cnv_typ,
- struct node *src));
- hidden novalue cnt_bufs Params((struct node *cnv_typ));
- hidden int icn_typ Params((struct node *n));
- hidden struct il_code *il_walk Params((struct node *n));
- hidden struct il_code *il_var Params((struct node *n));
- hidden int is_addr Params((struct node *dcltor, int modifier));
- hidden novalue lcl_tend Params((struct node *n));
- hidden int mrg_abstr Params((int sum, int typ));
- hidden int strct_typ Params((struct node *typ, int *is_reg));
-
- static int body_ret; /* RetInt, RetDbl, and/or RetOther for current body */
- static int ret_flag; /* DoesFail, DoesRet, and/or DoesSusp for current body */
- int fnc_ret; /* RetInt, RetDbl, RetNoVal, or RetSig for current func */
-
- #ifndef Rttx
-
- /*
- * body_prms is a list of symbol table entries for identifiers that must
- * be passed as parameters to the function implementing the current
- * body statement. The id_type of an identifier may be changed in the
- * symbol table while the body function is being produced; for example,
- * a tended descriptor is accessed through a parameter that is a pointer
- * to a descriptor, rather than being accessed as an element of a descriptor
- * array in a struct.
- */
- struct var_lst {
- struct sym_entry *sym;
- int id_type; /* saved value of id_type from sym */
- struct var_lst *next;
- };
- struct var_lst *body_prms;
- static struct var_lst *v_lst_free = NULL; /* free list for var_lst structs */
- int n_bdy_prms; /* number of entries in body_prms list */
- int rslt_loc; /* flag: function passed addr of result descriptor */
-
- char prfx3; /* 3rd prefix char; used for unique body func names */
-
- /*
- * in_line - place in the data base in-line code for an operation and
- * produce C functions for body statements.
- */
- novalue in_line(n)
- struct node *n;
- {
- struct sym_entry *sym;
- int i;
- int nvars;
- int ntend;
-
- prfx3 = ' '; /* reset 3rd prefix char for body functions */
-
- /*
- * Set up the local symbol table in the data base for the in-line code.
- * This symbol table has an array of entries for the tended variables
- * in the declare statement, if there is one. Determine how large the
- * array must be and create it.
- */
- ntend = 0;
- for (sym = dcl_stk->tended; sym != NULL; sym = sym->u.tnd_var.next)
- ++ntend;
- if (ntend == 0)
- cur_impl->tnds = NULL;
- else
- cur_impl->tnds = (struct tend_var *)alloc((unsigned int)
- (sizeof(struct tend_var) * ntend));
- cur_impl->ntnds = ntend;
- i = 0;
-
- /*
- * Go back through the declarations and fill in the array for the
- * tended part of the data base symbol table. Array entries contain
- * an indication of the type of tended declaration, the C code to
- * initialize the variable if there is any, and, for block pointer
- * declarations, the type of block. rtt's symbol table is updated to
- * contain the variable's offset into the data base's symbol table.
- * Note that paramters are considered part of the data base's symbol
- * table when computing the offset and il_indx initially contains
- * their number.
- */
- for (sym = dcl_stk->tended; sym != NULL; sym = sym->u.tnd_var.next) {
- cur_impl->tnds[i].var_type = sym->id_type;
- cur_impl->tnds[i].init = inlin_c(sym->u.tnd_var.init, 0);
- cur_impl->tnds[i].blk_name = sym->u.tnd_var.blk_name;
- sym->il_indx = il_indx++;
- ++i;
- }
-
- /*
- * The data base's symbol table also has entries for non-tended
- * variables from the declare statement. Each entry has the
- * identifier for the variable and the declaration (redundantly
- * including the identifier). Once again the offset for the data
- * base symbol table is stored in rtt's symbol table.
- */
- nvars = -il_indx; /* pre-subtract preceding number of entries */
- for (sym = decl_lst; sym != NULL; sym = sym->u.declare_var.next)
- sym->il_indx = il_indx++;
- nvars += il_indx; /* compute number of entries in this part of table */
- cur_impl->nvars = nvars;
- if (nvars > 0) {
- cur_impl->vars = (struct ord_var *)alloc((unsigned int)
- (sizeof(struct ord_var) * nvars));
- i = 0;
- for (sym = decl_lst; sym != NULL; sym = sym->u.declare_var.next) {
- cur_impl->vars[i].name = sym->image;
- cur_impl->vars[i].dcl = ilc_dcl(sym->u.declare_var.tqual,
- sym->u.declare_var.dcltor, sym->u.declare_var.init);
- ++i;
- }
- }
-
- abs_ret = NoAbstr; /* abstract clause not encountered yet */
- cur_impl->in_line = il_walk(n); /* produce in-line code for operation */
- }
-
- /*
- * il_walk - walk the syntax tree producing in-line code.
- */
- static struct il_code *il_walk(n)
- struct node *n;
- {
- struct token *t;
- struct node *n1;
- struct node *n2;
- struct il_code *il;
- struct il_code *il1;
- struct sym_entry *sym;
- struct init_tend *tnd;
- int ntend;
-
- if (n == NULL)
- return NULL;
-
- t = n->tok;
-
- switch (n->nd_id) {
- case PrefxNd:
- switch (t->tok_id) {
- case '{':
- /*
- * RTL code: { <actions> }
- */
- il = il_walk(n->u[0].child);
- break;
- case '!':
- /*
- * RTL type-checking and conversions: ! <simple-type-check>
- */
- il = new_il(IL_Bang, 1);
- il->u[0].fld = il_walk(n->u[0].child);
- break;
- case Body:
- /*
- * RTL code: body { <c-code> }
- */
- il = body_fnc(n);
- break;
- case Inline:
- /*
- * RTL code: inline { <c-code> }
- *
- * An in-line code "block" in the data base starts off
- * with a list of tended descriptors needed by the in-line
- * C code. The list indicates the kind of tended descriptor.
- * The list is determined by walking to the syntax tree
- * for the C code; tend_lst points to its beginning.
- * The last item in the block is the C code itself.
- */
- free_tend();
- lcl_tend(n);
- if (tend_lst == NULL)
- ntend = 0;
- else
- ntend = tend_lst->t_indx + 1;
- il = new_il(IL_Block, 2 + ntend);
- il->u[0].n = ntend;
- for (tnd = tend_lst; tnd != NULL; tnd = tnd->next)
- il->u[1 + tnd->t_indx].n = tnd->init_typ;
- il->u[ntend + 1].c_cd = inlin_c(n->u[0].child, 0);
- break;
- case Type:
- /*
- * RTL abstract type computation: type( <variable> )
- */
- il = new_il(IL_VarTyp, 1);
- il->u[0].fld = il_var(n->u[0].child);
- break;
- case Store:
- /*
- * RTL abstract type computation: store[ <type> ]
- */
- il = new_il(IL_Store, 1);
- il->u[0].fld = il_walk(n->u[0].child);
- break;
- }
- break;
- case PstfxNd:
- /*
- * RTL abstract type computation: <type> . <attrb_name>
- *
- * Each kind of attribute is given a different code in the
- * data base.
- */
- switch (t->tok_id) {
- case Lst_elem:
- il = new_il(IL_LstElm, 1);
- break;
- case Set_elem:
- il = new_il(IL_SetElm, 1);
- break;
- case Key:
- il = new_il(IL_TblKey, 1);
- break;
- case Tbl_elem:
- il = new_il(IL_TblElm, 1);
- break;
- case Default:
- il = new_il(IL_TblDft, 1);
- break;
- case All_fields:
- il = new_il(IL_Fields, 1);
- break;
- case Str_var:
- il = new_il(IL_StrVar, 1);
- break;
- case Trpd_tbl:
- il = new_il(IL_TrpTbl, 1);
- break;
- }
- il->u[0].fld = il_walk(n->u[0].child);
- break;
- case IcnTypNd:
- /*
- * RTL abstract type computation: <icon-type>
- */
- il = new_il(IL_IcnTyp, 1);
- il->u[0].n = icn_typ(n->u[0].child);
- break;
- case BinryNd:
- switch (t->tok_id) {
- case Runerr:
- /*
- * RTL code: runerr( <message-number> )
- * runerr( <message-number>, <descriptor> )
- */
- if (n->u[1].child == NULL)
- il = new_il(IL_Err1, 1);
- else {
- il = new_il(IL_Err2, 2);
- il->u[1].fld = il_var(n->u[1].child);
- }
- il->u[0].n = atol(n->u[0].child->tok->image);
- /*
- * Execution cannot continue on this execution path, so
- * it contributes nothing to the location of parameters.
- */
- for (sym = params; sym != NULL; sym = sym->u.param_info.next)
- if (sym->id_type & DrfPrm)
- sym->u.param_info.cur_loc = 0;
- break;
- case And:
- /*
- * RTL type-checking and conversions:
- * <type-check> && <type_check>
- */
- il = new_il(IL_And, 2);
- il->u[0].fld = il_walk(n->u[0].child);
- il->u[1].fld = il_walk(n->u[1].child);
- break;
- case Is:
- /*
- * RTL type-checking and conversions:
- * is: <icon-type> ( <variable> )
- */
- il = new_il(IL_Is, 2);
- il->u[0].n = icn_typ(n->u[0].child);
- il->u[1].fld = il_var(n->u[1].child);
- break;
- case '=':
- /*
- * RTL abstract type computation: store[ <type> ] = <type>
- */
- il = new_il(IL_TpAsgn, 2);
- il->u[0].fld = il_walk(n->u[0].child);
- il->u[1].fld = il_walk(n->u[1].child);
- break;
- case Incr: /* union */
- /*
- * RTL abstract type computation: <type> ++ <type>
- */
- il = new_il(IL_Union, 2);
- il->u[0].fld = il_walk(n->u[0].child);
- il->u[1].fld = il_walk(n->u[1].child);
- break;
- case Intersect:
- /*
- * RTL abstract type computation: <type> ** <type>
- */
- il = new_il(IL_Inter, 2);
- il->u[0].fld = il_walk(n->u[0].child);
- il->u[1].fld = il_walk(n->u[1].child);
- break;
- case New: {
- /*
- * RTL abstract type computation:
- * new <icon-type> ( <type> , ... )
- */
- struct node *typ;
- struct node *args;
- int typ_cd;
- int nargs;
-
- typ = n->u[0].child;
- args = n->u[1].child;
-
- /*
- * Determine the number of arguments expected for this
- * structure type.
- */
- typ_cd = icn_typ(typ);
- switch (typ_cd) {
- case TypList:
- case TypSet:
- case TypTvStr:
- case TypTvTbl:
- nargs = 1;
- break;
- case TypTbl:
- nargs = 3;
- break;
- default:
- errt2(typ->tok,typ->tok->image," is not a structure type.");
- }
-
- /*
- * Create the "new" construct for the data base with its type
- * code and arguments.
- */
- il = new_il(IL_New, 2 + nargs);
- il->u[0].n = typ_cd;
- il->u[1].n = nargs;
- while (nargs > 1) {
- if (args->nd_id == CommaNd)
- il->u[1 + nargs].fld = il_walk(args->u[1].child);
- else
- errt2(typ->tok, "too few arguments for new",
- typ->tok->image);
- args = args->u[0].child;
- --nargs;
- }
- if (args->nd_id == CommaNd)
- errt2(typ->tok, "too many arguments for new",typ->tok->image);
- il->u[2].fld = il_walk(args);
- }
- break;
- }
- break;
- case ConCatNd:
- /*
- * "Glue" for two constructs.
- */
- il = new_il(IL_Lst, 2);
- il->u[0].fld = il_walk(n->u[0].child);
- il->u[1].fld = il_walk(n->u[1].child);
- break;
- case AbstrNd:
- /*
- * RTL code: abstract { <type-computations> }
- *
- * Remember the return statement if there is one. It is used for
- * type checking when types are easily determined.
- */
- il = new_il(IL_Abstr, 2);
- il->u[0].fld = il_walk(n->u[0].child);
- il1 = il_walk(n->u[1].child);
- il->u[1].fld = il1;
- if (il1 != NULL) {
- if (abs_ret != NoAbstr)
- errt1(t,"only one abstract return may be on any execution path");
- if (il1->il_type == IL_IcnTyp || il1->il_type == IL_New)
- abs_ret = il1->u[0].n;
- else
- abs_ret = SomeType;
- }
- break;
- case TrnryNd:
- switch (t->tok_id) {
- case If: {
- /*
- * RTL code for "if" statements:
- * if <type-check> then <action>
- * if <type-check> then <action> else <action>
- *
- * <type-check> may include parameter conversions that create
- * new scoping. It is necessary to keep track of paramter
- * types and locations along success and failure paths of
- * these conversions. The "then" and "else" actions may
- * also establish new scopes (if a parameter is used within
- * a overlapping scopes that conflict, it has already been
- * detected).
- *
- * The "then" and "else" actions may contain abstract return
- * statements. The types of these must be "merged" in case
- * type checking must be done on real return or suspend
- * statements following the "if".
- */
- int *then_prms = NULL;
- int *else_prms;
- struct node *cond;
- struct node *else_nd;
- int sav_absret;
- int new_absret;
-
- /*
- * Save the current parameter locations. These are in
- * effect on the failure path of any type conversions
- * in the condition of the "if". Also remember any
- * information from astract returns.
- */
- else_prms = new_prmloc();
- sv_prmloc(else_prms);
- sav_absret = new_absret = abs_ret;
-
- cond = n->u[0].child;
- else_nd = n->u[2].child;
-
- if (else_nd == NULL)
- il = new_il(IL_If1, 2);
- else
- il = new_il(IL_If2, 3);
- il->u[0].fld = il_walk(cond);
- /*
- * If the condition is negated, the failure path is to the "then"
- * and the success path is to the "else".
- */
- if (cond->nd_id == PrefxNd && cond->tok->tok_id == '!') {
- then_prms = else_prms;
- else_prms = new_prmloc();
- sv_prmloc(else_prms);
- ld_prmloc(then_prms);
- }
- il->u[1].fld = il_walk(n->u[1].child); /* then ... */
- if (else_nd == NULL) {
- mrg_prmloc(else_prms);
- ld_prmloc(else_prms);
- }
- else {
- if (then_prms == NULL)
- then_prms = new_prmloc();
- sv_prmloc(then_prms);
- ld_prmloc(else_prms);
- new_absret = mrg_abstr(new_absret, abs_ret);
- abs_ret = sav_absret;
- il->u[2].fld = il_walk(else_nd);
- mrg_prmloc(then_prms);
- ld_prmloc(then_prms);
- }
- abs_ret = mrg_abstr(new_absret, abs_ret);
- if (then_prms != NULL)
- free(then_prms);
- if (else_prms != NULL)
- free(else_prms);
- }
- break;
- case Len_case: {
- /*
- * RTL code:
- * len_case <variable> of {
- * <integer>: <action>
- * ...
- * default: <action>
- * }
- */
- int *strt_prms;
- int *end_prms;
- int n_cases;
- int indx;
- int sav_absret;
- int new_absret;
-
- /*
- * A case may contain parameter conversions that create new
- * scopes. Remember the parameter locations at the start
- * of the len_case statement. Also remember information
- * about abstract type returns.
- */
- strt_prms = new_prmloc();
- sv_prmloc(strt_prms);
- end_prms = new_prmloc();
- sav_absret = new_absret = abs_ret;
-
- /*
- * Count the number of cases; there is at least one.
- */
- n_cases = 1;
- for (n1 = n->u[1].child; n1->nd_id == ConCatNd;
- n1 = n1->u[0].child)
- ++n_cases;
-
- /*
- * The data base entry has one slot for the number of cases,
- * one for the default clause, and two for each case. A
- * case includes a selection integer and an action.
- */
- il = new_il(IL_Lcase, 2 + 2 * n_cases);
- il->u[0].n = n_cases;
-
- /*
- * Go through the cases, adding them to the data base entry.
- * Merge resulting parameter locations and information
- * about abstract type returns, then restore the starting
- * information for the next case.
- */
- indx = 2 * n_cases;
- for (n1 = n->u[1].child; n1->nd_id == ConCatNd;
- n1 = n1->u[0].child) {
- il->u[indx--].fld = il_walk(n1->u[1].child->u[0].child);
- il->u[indx--].n = atol(n1->u[1].child->tok->image);
- mrg_prmloc(end_prms);
- ld_prmloc(strt_prms);
- new_absret = mrg_abstr(new_absret, abs_ret);
- abs_ret = sav_absret;
- }
- /*
- * Last case.
- */
- il->u[indx--].fld = il_walk(n1->u[0].child);
- il->u[indx].n = atol(n1->tok->image);
- mrg_prmloc(end_prms);
- ld_prmloc(strt_prms);
- new_absret = mrg_abstr(new_absret, abs_ret);
- abs_ret = sav_absret;
- /*
- * Default clause.
- */
- il->u[1 + 2 * n_cases].fld = il_walk(n->u[2].child);
- mrg_prmloc(end_prms);
- ld_prmloc(end_prms);
- abs_ret = mrg_abstr(new_absret, abs_ret);
- if (strt_prms != NULL)
- free(strt_prms);
- if (end_prms != NULL)
- free(end_prms);
- }
- break;
- case Type_case: {
- /*
- * RTL code:
- * type_case <variable> of {
- * <icon_type> : ... <icon_type> : <action>
- * ...
- * }
- *
- * last clause may be: default: <action>
- */
- struct node *sel;
- int *strt_prms;
- int *end_prms;
- int *typ_vect;
- int n_case;
- int n_typ;
- int n_fld;
- int sav_absret;
- int new_absret;
-
- /*
- * A case may contain parameter conversions that create new
- * scopes. Remember the parameter locations at the start
- * of the type_case statement. Also remember information
- * about abstract type returns.
- */
- strt_prms = new_prmloc();
- sv_prmloc(strt_prms);
- end_prms = new_prmloc();
- sav_absret = new_absret = abs_ret;
-
- /*
- * Count the number of cases.
- */
- n_case = 0;
- for (n1 = n->u[1].child; n1 != NULL; n1 = n1->u[0].child)
- ++n_case;
-
- /*
- * The data base entry has one slot for the variable whose
- * type is being tested, one for the number cases, three
- * for each case, and, if there is default clause, one
- * for it. Each case includes the number of types selected
- * by the case, a vectors of those types, and the action
- * for the case.
- */
- if (n->u[2].child == NULL) {
- il = new_il(IL_Tcase1, 3 * n_case + 2);
- il->u[0].fld = il_var(n->u[0].child);
- }
- else {
- /*
- * There is a default clause.
- */
- il = new_il(IL_Tcase2, 3 * n_case + 3);
- il->u[0].fld = il_var(n->u[0].child);
- il->u[3 * n_case + 2].fld = il_walk(n->u[2].child);
- mrg_prmloc(end_prms);
- ld_prmloc(strt_prms);
- }
- il->u[1].n = n_case;
-
- /*
- * Go through the cases, adding them to the data base entry.
- * Merge resulting parameter locations and information
- * about abstract type returns, then restore the starting
- * information for the next case.
- */
- n_fld = 2;
- for (n1 = n->u[1].child; n1 != NULL; n1 = n1->u[0].child) {
- /*
- * Determine the number types selected by the case and
- * put the types in a vector.
- */
- sel = n1->u[1].child;
- n_typ = 0;
- for (n2 = sel->u[0].child; n2 != NULL; n2 = n2->u[0].child)
- n_typ++;
- il->u[n_fld++].n = n_typ;
- typ_vect = (int *)alloc((unsigned int)(sizeof(int) * n_typ));
- il->u[n_fld++].vect = typ_vect;
- n_typ = 0;
- for (n2 = sel->u[0].child; n2 != NULL; n2 = n2->u[0].child)
- typ_vect[n_typ++] = icn_typ(n2->u[1].child);
- /*
- * Add code for the case to the data base entry.
- */
- new_absret = mrg_abstr(new_absret, abs_ret);
- abs_ret = sav_absret;
- il->u[n_fld++].fld = il_walk(sel->u[1].child);
- mrg_prmloc(end_prms);
- ld_prmloc(strt_prms);
- }
- ld_prmloc(end_prms);
- abs_ret = mrg_abstr(new_absret, abs_ret);
- if (strt_prms != NULL)
- free(strt_prms);
- if (end_prms != NULL)
- free(end_prms);
- }
- break;
- case Cnv: {
- /*
- * RTL code: cnv: <type> ( <source> )
- * cnv: <type> ( <source> , <destination> )
- */
- struct node *typ;
- struct node *src;
- struct node *dst;
-
- typ = n->u[0].child;
- src = n->u[1].child;
- dst = n->u[2].child;
- if (dst == NULL) {
- il = new_il(IL_Cnv1, 2);
- il->u[0].n = icn_typ(typ);
- il->u[1].fld = il_var(src);
- /*
- * This "in-place" conversion may create a new scope for the
- * source parameter.
- */
- chng_ploc(typ, src);
- }
- else {
- il = new_il(IL_Cnv2, 3);
- il->u[0].n = icn_typ(typ);
- il->u[1].fld = il_var(src);
- il->u[2].c_cd = inlin_c(dst, 1);
- }
- }
- break;
- }
- break;
- case QuadNd: {
- /*
- * RTL code: def: <type> ( <source> , <default>)
- * def: <type> ( <source> , <default> , <destination> )
- */
- struct node *typ;
- struct node *src;
- struct node *dflt;
- struct node *dst;
-
- typ = n->u[0].child;
- src = n->u[1].child;
- dflt = n->u[2].child;
- dst = n->u[3].child;
- if (dst == NULL) {
- il = new_il(IL_Def1, 3);
- il->u[0].n = icn_typ(typ);
- il->u[1].fld = il_var(src);
- il->u[2].c_cd = inlin_c(dflt, 0);
- /*
- * This "in-place" conversion may create a new scope for the
- * source parameter.
- */
- chng_ploc(typ, src);
- }
- else {
- il = new_il(IL_Def2, 4);
- il->u[0].n = icn_typ(typ);
- il->u[1].fld = il_var(src);
- il->u[2].c_cd = inlin_c(dflt, 0);
- il->u[3].c_cd = inlin_c(dst, 1);
- }
- }
- break;
- }
- return il;
- }
-
- /*
- * il_var - produce in-line code in the data base for varibel references.
- * These include both simple identifiers and subscripted identifiers.
- */
- static struct il_code *il_var(n)
- struct node *n;
- {
- struct il_code *il;
-
- if (n->nd_id == SymNd) {
- il = new_il(IL_Var, 1);
- il->u[0].n = n->u[0].sym->il_indx; /* offset into data base sym. tab. */
- }
- else if (n->nd_id == BinryNd) {
- /*
- * A subscripted variable.
- */
- il = new_il(IL_Subscr, 2);
- il->u[0].n = n->u[0].child->u[0].sym->il_indx; /* sym. tab. offset */
- il->u[1].n = atol(n->u[1].child->tok->image); /* subscript */
- }
- else
- errt2(n->tok, "undeclared identifier: ", n->tok->image);
- return il;
- }
-
- /*
- * icn_typ - convert a type node into a type code for the internal
- * representation of the data base.
- */
- static int icn_typ(typ)
- struct node *typ;
- {
- if (typ->nd_id == PrimryNd)
- switch (typ->tok->tok_id) {
- case Empty_type:
- return TypEmpty;
- case Null:
- return TypNull;
- case String:
- return TypStr;
- case Cset:
- return TypCset;
- case Integer:
- return TypInt;
- case Real:
- return TypReal;
- case File:
- return TypFile;
- case List:
- return TypList;
- case Set:
- return TypSet;
- case Table:
- return TypTbl;
- case Record:
- return TypRec;
- case Procedure:
- return TypProc;
- case Co_expression:
- return TypCoExp;
- case Variable:
- return TypVar;
- case Tvsubs:
- return TypTvStr;
- case Tvtbl:
- return TypTvTbl;
- case Kywdint:
- return TypKyInt;
- case Kywdpos:
- return TypKyPos;
- case Kywdsubj:
- return TypKySub;
- case C_Integer:
- return TypCInt;
- case C_Double:
- return TypCDbl;
- case C_String:
- return TypCStr;
- case Tmp_string:
- return TypTStr;
- case Tmp_cset:
- return TypTCset;
- }
- else { /* must be exact conversion */
- if (typ->tok->tok_id == Integer)
- return TypEInt;
- else /* C_Integer */
- return TypECInt;
- }
- err1("rtt internal error detected in function icn_typ()");
- /* NOTREACHED */
- }
-
-
- /*
- * body_anlz - walk the syntax tree for the C code in a body statment,
- * analyzing the code to determine the iterface needed by the C function
- * which will implement it. Also determine how many buffers are needed.
- * The value returned inticates whether it is possible for execution
- * to fall through the the code; knowing when execution does not fall
- * through helps produce better code.
- */
- static int body_anlz(n, does_break, may_mod)
- struct node *n; /* subtree being analyzed */
- int *does_break; /* output flag: subtree contains "break;" */
- int may_mod; /* input flag: this subtree might be assigned to */
- {
- struct token *t;
- struct sym_entry *sym;
- struct var_lst *var_ref;
- int break_chk = 0;
-
- if (n == NULL)
- return 1;
-
- t = n->tok;
-
- switch (n->nd_id) {
- case PrimryNd:
- switch (t->tok_id) {
- case Fail:
- ret_flag |= DoesFail;
- return 0;
- case Errorfail:
- ret_flag |= DoesEFail;
- return 0;
- case Break:
- *does_break = 1;
- return 1;
- default: /* do nothing special */
- return 1;
- }
- case PrefxNd:
- switch (t->tok_id) {
- case Return:
- ret_flag |= DoesRet;
- chkrettyp(n->u[0].child); /* check for returning of C value */
- body_anlz(n->u[0].child, does_break, 0);
- return 0;
- case Suspend:
- ret_flag |= DoesSusp;
- chkrettyp(n->u[0].child); /* check for returning of C value */
- body_anlz(n->u[0].child, does_break, 0);
- return 1;
- case '(':
- /*
- * parenthesized expression: pass along may_mod.
- */
- return body_anlz(n->u[0].child, does_break, may_mod);
- case Incr: /* ++ */
- case Decr: /* -- */
- case '&':
- /*
- * Operand may be modified. Note that inclusion of the
- * "address of" operator insures conservative results
- * as we don't know how the address will be used.
- */
- body_anlz(n->u[0].child, does_break, 1);
- return 1;
- case Goto:
- body_anlz(n->u[0].child, does_break, 0);
- return 0;
- default: /* unary operations the need nothing special */
- body_anlz(n->u[0].child, does_break, 0);
- return 1;
- }
- case PstfxNd:
- if (t->tok_id == ';')
- body_anlz(n->u[0].child, does_break, 0);
- else {
- /*
- * C expressions: <expr> ++
- * <expr> --
- *
- * modify operand
- */
- body_anlz(n->u[0].child, does_break, 1);
- }
- return 1;
- case PreSpcNd:
- body_anlz(n->u[0].child, does_break, 0);
- return 1;
- case SymNd:
- /*
- * This is an identifier.
- */
- sym = n->u[0].sym;
- if (sym->id_type == RsltLoc) {
- /*
- * Note that this body code explicitly references the result
- * location of the operation.
- */
- rslt_loc = 1;
- }
- else if (sym->nest_lvl == 2) {
- /*
- * This variable is local to the operation, but declared outside
- * the body. It must passed as a parameter to the function.
- * See if it is in the parameter list yet.
- */
- if (!(sym->id_type & PrmMark)) {
- sym->id_type |= PrmMark;
- if ((var_ref = v_lst_free) == NULL)
- var_ref = NewStruct(var_lst);
- else
- v_lst_free = v_lst_free->next;
- var_ref->sym = sym;
- var_ref->next = body_prms;
- body_prms = var_ref;
- ++n_bdy_prms;
- }
-
- /*
- * Note if the variable might be assigned to.
- */
- sym->may_mod |= may_mod;
- }
- return 1;
- case BinryNd:
- switch (t->tok_id) {
- case '[': /* subscripting */
- case '.':
- /*
- * Assignments will modify left operand.
- */
- body_anlz(n->u[0].child, does_break, may_mod);
- body_anlz(n->u[1].child, does_break, 0);
- return 1;
- case Switch:
- /*
- * "break;" statements in body of switch statment do
- * not effect outer loops so pass along a new flag
- * for does_break.
- */
- body_anlz(n->u[0].child, does_break, 0);
- body_anlz(n->u[1].child, &break_chk, 0);
- return 1;
- case While: {
- struct node *n0 = n->u[0].child;
- body_anlz(n0, does_break, 0);
- body_anlz(n->u[1].child, &break_chk, 0);
- /*
- * check for an infinite loop, while (1) ... :
- * a condition consisting of an IntConst with image=="1"
- * and no breaks in the body.
- */
- if (n0->nd_id == PrimryNd && n0->tok->tok_id == IntConst &&
- !strcmp(n0->tok->image,"1") && !break_chk)
- return 0;
- return 1;
- }
- case Do:
- /*
- * Any "break;" statements in the body do not effect
- * outer loops so pass along a new flag for does_break.
- */
- body_anlz(n->u[0].child, &break_chk, 0);
- body_anlz(n->u[1].child, does_break, 0);
- return 1;
- case Runerr:
- body_anlz(n->u[0].child, does_break, 0);
- body_anlz(n->u[1].child, does_break, 0);
- ret_flag |= DoesEFail; /* possibler error failure */
- return 0;
- case '=':
- case MultAsgn: /* *= */
- case DivAsgn: /* /= */
- case ModAsgn: /* %= */
- case PlusAsgn: /* += */
- case MinusAsgn: /* -= */
- case LShftAsgn: /* <<= */
- case RShftAsgn: /* >>= */
- case AndAsgn: /* &= */
- case XorAsgn: /* ^= */
- case OrAsgn: /* |= */
- /*
- * Left operand is modified.
- */
- body_anlz(n->u[0].child, does_break, 1);
- body_anlz(n->u[1].child, does_break, 0);
- return 1;
- default: /* binary operations that need nothing special */
- body_anlz(n->u[0].child, does_break, 0);
- body_anlz(n->u[1].child, does_break, 0);
- return 1;
- }
- case LstNd:
- case ConCatNd:
- case CommaNd:
- case StrDclNd:
- /*
- * Binary nodes that need nothing special here. For some, whether
- * execution falls through depends on the second operand.
- */
- body_anlz(n->u[0].child, does_break, 0);
- return body_anlz(n->u[1].child, does_break, 0);
- case CompNd:
- /*
- * Compound statement, look only at executable code.
- */
- return body_anlz(n->u[2].child, does_break, 0);
- case TrnryNd:
- switch (t->tok_id) {
- case Cnv:
- /*
- * extended C code: cnv: <type> ( <source> )
- * cnv: <type> ( <source> , <destination> )
- *
- * For some conversions, buffers may have to be allocated.
- * An explicit destination must be marked as modified.
- */
- cnt_bufs(n->u[0].child);
- body_anlz(n->u[1].child, does_break, 0);
- body_anlz(n->u[2].child, does_break, 1);
- return 1;
- case If:
- /*
- * Execution falls through an if statement if it falls
- * through either branch. A null "else" branch always
- * falls through.
- */
- body_anlz(n->u[0].child, does_break, 0);
- return body_anlz(n->u[1].child, does_break, 0) |
- body_anlz(n->u[2].child, does_break, 0);
- default: /* nothing special is needed for these ternary nodes */
- body_anlz(n->u[0].child, does_break, 0);
- body_anlz(n->u[1].child, does_break, 0);
- body_anlz(n->u[2].child, does_break, 0);
- return 1;
- }
- case QuadNd:
- if (t->tok_id == Def) {
- /*
- * extended C code:
- * def: <type> ( <source> , <default> )
- * def: <type> ( <source> , <default> , <destination> )
- *
- * For some conversions, buffers may have to be allocated.
- * An explicit destination must be marked as modified.
- */
- cnt_bufs(n->u[0].child);
- body_anlz(n->u[1].child, does_break, 0);
- body_anlz(n->u[2].child, does_break, 0);
- body_anlz(n->u[3].child, does_break, 1);
- return 1;
- }
- else { /* for */
- /*
- * Check for an infinite loop: for (<expr>; ; <expr> ) ...
- *
- * No ending condition and no breaks in the body.
- */
- body_anlz(n->u[0].child, does_break, 0);
- body_anlz(n->u[1].child, does_break, 0);
- body_anlz(n->u[2].child, does_break, 0);
- body_anlz(n->u[3].child, &break_chk, 0);
- if (n->u[1].child == NULL && !break_chk)
- return 0;
- else
- return 1;
- }
- }
- err1("rtt internal error detected in function body_anlz()");
- /* NOTREACHED */
- }
-
- /*
- * lcl_tend - allocate any tended variables needed in this body or inline
- * statement.
- */
- static novalue lcl_tend(n)
- struct node *n;
- {
- struct sym_entry *sym;
-
- if (n == NULL)
- return;
-
- /*
- * Walk the syntax tree until a block with declarations is found.
- */
- switch (n->nd_id) {
- case PrefxNd:
- case PstfxNd:
- case PreSpcNd:
- lcl_tend(n->u[0].child);
- break;
- case BinryNd:
- case LstNd:
- case ConCatNd:
- case CommaNd:
- case StrDclNd:
- lcl_tend(n->u[0].child);
- lcl_tend(n->u[1].child);
- break;
- case CompNd:
- /*
- * Allocate the tended variables in this block, noting that the
- * level of nesting in this C funciton is one less than in the
- * operation as a whole. Then mark the tended slots as free for
- * use in the next block.
- */
- for (sym = n->u[1].sym; sym != NULL; sym = sym->u.tnd_var.next) {
- sym->t_indx = alloc_tnd(sym->id_type, sym->u.tnd_var.init,
- sym->nest_lvl - 1);
- }
- lcl_tend(n->u[2].child);
- sym = n->u[1].sym;
- if (sym != NULL)
- unuse(tend_lst, sym->nest_lvl - 1);
- break;
- case TrnryNd:
- lcl_tend(n->u[0].child);
- lcl_tend(n->u[1].child);
- lcl_tend(n->u[2].child);
- break;
- case QuadNd:
- lcl_tend(n->u[0].child);
- lcl_tend(n->u[1].child);
- lcl_tend(n->u[2].child);
- lcl_tend(n->u[3].child);
- break;
- }
- }
-
- /*
- * chkrettyp - check type of return to see if it is a C integer or a
- * C double and make note of what is found.
- */
- static novalue chkrettyp(n)
- struct node *n;
- {
- if (n->nd_id == PrefxNd && n->tok != NULL) {
- switch (n->tok->tok_id) {
- case C_Integer:
- body_ret |= RetInt;
- return;
- case C_Double:
- body_ret |= RetDbl;
- return;
- }
- }
- body_ret |= RetOther;
- }
-
- /*
- * body_fnc - produce the function which implements a body statement.
- */
- static struct il_code *body_fnc(n)
- struct node *n;
- {
- struct node *compound;
- struct node *dcls;
- struct node *stmts;
- struct var_lst *var_ref;
- struct sym_entry *sym;
- struct il_code *il;
- int fall_thru; /* flag: control can fall through end of body */
- int num_sigs; /* number of different signals function may return */
- int bprm_indx;
- int first;
- int is_reg;
- int strct;
- int addr;
- int by_ref;
- int just_desc;
- int dummy_int;
- char buf1[6];
- char buf[MaxFileName];
- char *cname;
-
- /*
- * Figure out the next character to use as the 3rd prefix for the
- * name of this body function.
- */
- if (prfx3 == ' ')
- prfx3 = '0';
- else if (prfx3 == '9')
- prfx3 = 'a';
- else if (prfx3 == 'z')
- errt2(n->tok, "more than 26 body statements in", cur_impl->name);
- else
- ++prfx3;
-
- /*
- * Free any old body parameters and tended locations.
- */
- while (body_prms != NULL) {
- var_ref = body_prms;
- body_prms = body_prms->next;
- var_ref->next = v_lst_free;
- v_lst_free = var_ref;
- }
- free_tend();
-
- /*
- * Locate the outer declarations and statements from the body clause.
- */
- compound = n->u[0].child;
- dcls = compound->u[0].child;
- stmts = compound->u[2].child;
-
- /*
- * Analyze the body code to determine what the function's interface
- * needs. body_anlz() does the work after the counters and flags
- * are initialized.
- /*
- n_tmp_str = 0; /* number of tempory string buffers neeeded */
- n_tmp_cset = 0; /* number of tempory cset buffers needed */
- nxt_sbuf = 0; /* next string buffer index; used in code generation */
- nxt_cbuf = 0; /* next cset buffer index; used in code generation */
- n_bdy_prms = 0; /* number of variables needed as body function parameters */
- body_ret = 0; /* flag: C values and/or non-C values returned */
- ret_flag = 0; /* flag: return, suspend, fail, error fail */
- rslt_loc = 0; /* flag: body code needs operations result location */
- fall_thru = body_anlz(compound, &dummy_int, 0);
- lcl_tend(n); /* allocate tended descriptors needed */
-
-
- /*
- * Use the letter indicating operation type along with body function
- * prefixes to construct the name of the file to hold the C code.
- */
- sprintf(buf1, "%c_%c%c%c", lc_letter, prfx1, prfx2, prfx3);
- cname = salloc(makename(buf, SourceDir, buf1, CSuffix));
- if ((out_file = fopen(cname, "w")) == NULL)
- err2("cannot open output file", cname);
-
- prologue(); /* output standard comments and preprocessor directives */
-
- /*
- * If the function produces a unique signal, the function need not actually
- * return it, and we may be able to use the return value for something
- * else. See if this is true.
- */
- num_sigs = 0;
- if (ret_flag & DoesRet)
- ++num_sigs;
- if (ret_flag & (DoesFail | DoesEFail))
- ++num_sigs;
- if (ret_flag & DoesSusp)
- num_sigs += 2; /* something > 1 (success cont. may return anything) */
- if (fall_thru) {
- ret_flag |= DoesFThru;
- ++num_sigs;
- }
-
- if (num_sigs > 1)
- fnc_ret = RetSig; /* Function must return a signal */
- else {
- /*
- * If the body returns a C_integer or a C_double, we can make the
- * function directly return the C value and the compiler can decide
- * whether to construct a descriptor.
- */
- if (body_ret == RetInt || body_ret == RetDbl)
- fnc_ret = body_ret;
- else
- fnc_ret = RetNoVal; /* Function returns nothing directly */
- }
-
- /*
- * Decide whether the function needs to to be passed an explicit result
- * location (the case where "result" is explicitly referenced is handled
- * while analyzing the body). suspend always uses the result location.
- * return uses the result location unless the function directly
- * returns a C value.
- */
- if (ret_flag & DoesSusp)
- rslt_loc = 1;
- else if ((ret_flag & DoesRet) && (fnc_ret != RetInt && fnc_ret != RetDbl))
- rslt_loc = 1;
-
- /*
- * The data base entry for the call to the body function has 8 slots
- * for standard interface information and 2 slots for each parameter.
- */
- il = new_il(IL_Call, 8 + 2 * n_bdy_prms);
- il->u[0].n = 0; /* reserved for interanl use by compiler */
- il->u[1].n = prfx3;
- il->u[2].n = fnc_ret;
- il->u[3].n = ret_flag;
- il->u[4].n = rslt_loc;
- il->u[5].n = 0; /* number of string buffers to pass in: set below */
- il->u[6].n = 0; /* number of cset buffers to pass in: set below */
- il->u[7].n = n_bdy_prms;
- bprm_indx = 8;
-
- /*
- * Write the C function header for the body function.
- */
- switch (fnc_ret) {
- case RetSig:
- fprintf(out_file, "int ");
- break;
- case RetInt:
- fprintf(out_file, "C_integer ");
- break;
- case RetDbl:
- fprintf(out_file, "double ");
- break;
- case RetNoVal:
- fprintf(out_file, "novalue ");
- break;
- }
- fprintf(out_file, " %c%c%c%c_%s(", uc_letter, prfx1, prfx2, prfx3,
- cur_impl->name);
- fname = cname;
- line = 7;
-
- /*
- * Write parameter list, first the paranthesized list of names. Start
- * with names of RLT variables that must be passed in.
- */
- first = 1;
- for (var_ref = body_prms; var_ref != NULL; var_ref = var_ref->next) {
- sym = var_ref->sym;
- sym->id_type &= ~PrmMark; /* unmark entry */
- if (first)
- first = 0;
- else
- prt_str(", ", IndentInc);
- prt_str(sym->image, IndentInc);
- }
-
- if (fall_thru) {
- /*
- * We cannot allocate string and cset buffers locally, so any
- * that are needed must be parameters.
- */
- if (n_tmp_str > 0) {
- if (first)
- first = 0;
- else
- prt_str(", ", IndentInc);
- prt_str("r_sbuf", IndentInc);
- }
- if (n_tmp_cset > 0) {
- if (first)
- first = 0;
- else
- prt_str(", ", IndentInc);
- prt_str("r_cbuf", IndentInc);
- }
- }
-
- /*
- * If the result location is needed it is passed as the next parameter.
- */
- if (rslt_loc) {
- if (first)
- first = 0;
- else
- prt_str(", ", IndentInc);
- prt_str("r_rslt", IndentInc);
- }
-
- /*
- * If a success continuation is needed, it goes last.
- */
- if (ret_flag & DoesSusp) {
- if (!first)
- prt_str(", ", IndentInc);
- prt_str("r_s_cont", IndentInc);
- }
- prt_str(")", IndentInc);
- ForceNl();
-
- /*
- * Go through the parameters to this function writing out declarations
- * and filling in rest of data base entry. Start with RLT variables.
- */
- for (var_ref = body_prms; var_ref != NULL; var_ref = var_ref->next) {
- /*
- * Each parameters has two slots in the data base entry. One
- * is the declaration for use by iconc in producing function
- * prototypes. The other is the argument that must be passed as
- * part of the call generated by iconc.
- *
- * Determine whether the parameter is passed by reference or by
- * value (flag by_ref). Tended variables that refer to just the
- * vword of a descriptor require special handling. They must
- * be passed to the body function as a pointer to the entire
- * decriptor and not just the vword. Within the function the
- * parameter is then accessed as x->vword... This is indicated
- * by the paramter flag just_desc.
- */
- sym = var_ref->sym;
- var_ref->id_type = sym->id_type; /* save old id_type */
- by_ref = 0;
- just_desc = 0;
- switch (sym->id_type) {
- case TndDesc: /* tended struct descrip x */
- by_ref = 1;
- il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym);
- break;
- case TndStr: /* tended char *x */
- case TndBlk: /* tended struct b_??? *x or tended union block *x */
- by_ref = 1;
- just_desc = 1;
- il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym);
- break;
- case RtParm: /* undereferenced RTL parameter */
- case DrfPrm: /* dereferenced RTL parameter */
- switch (sym->u.param_info.cur_loc) {
- case PrmTend: /* plain parameter: descriptor */
- by_ref = 1;
- il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym);
- break;
- case PrmCStr: /* parameter converted to a tended C string */
- by_ref = 1;
- just_desc = 1;
- il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym);
- break;
- case PrmInt: /* parameter converted to a C integer */
- sym->id_type = OtherDcl;
- if (var_ref->sym->may_mod && fall_thru)
- by_ref = 1;
- il->u[bprm_indx++].c_cd = simpl_dcl("C_integer ", by_ref,
- sym);
- break;
- case PrmDbl: /* parameter converted to a C double */
- sym->id_type = OtherDcl;
- if (var_ref->sym->may_mod && fall_thru)
- by_ref = 1;
- il->u[bprm_indx++].c_cd = simpl_dcl("double ", by_ref, sym);
- break;
- }
- break;
- case RtParm | VarPrm:
- case DrfPrm | VarPrm:
- /*
- * Variable part of RTL parameter list: already descriptor pointer.
- */
- sym->id_type = OtherDcl;
- il->u[bprm_indx++].c_cd = simpl_dcl("dptr ", 0, sym);
- break;
- case VArgLen:
- /*
- * Number of elements in variable part of RTL paramter list:
- * integer but not a true variable.
- */
- sym->id_type = OtherDcl;
- il->u[bprm_indx++].c_cd = simpl_dcl("int ", 0, sym);
- break;
- case OtherDcl:
- is_reg = 0;
- /*
- * Pass by reference if it is a structure or union type (but
- * not if it is a pointer to one) or if the variable is
- * modified and it is possible to execute more code after the
- * body. WARNING: crude assumptions are made for typedef
- * types.
- */
- strct = strct_typ(sym->u.declare_var.tqual, &is_reg);
- addr = is_addr(sym->u.declare_var.dcltor, '\0');
- if ((strct && !addr) || (var_ref->sym->may_mod && fall_thru))
- by_ref = 1;
- if (is_reg && by_ref)
- errt2(sym->u.declare_var.dcltor->u[1].child->tok, sym->image,
- " may not be declared 'register'");
-
- il->u[bprm_indx++].c_cd = parm_dcl(by_ref, sym);
- break;
- }
-
- /*
- * Determine what the iconc generated argument in a function
- * call should look like.
- */
- il->u[bprm_indx++].c_cd = bdy_prm(by_ref, just_desc, sym,
- var_ref->sym->may_mod);
-
- /*
- * If it a call-by-reference parameter, indicate that the level
- * of indirection must be taken into account within the function
- * body.
- */
- if (by_ref)
- sym->id_type |= ByRef;
- }
-
- if (fall_thru) {
- /*
- * Write declarations for any needed buffer parameters.
- */
- if (n_tmp_str > 0) {
- prt_str("char (*r_sbuf)[MaxCvtLen];", 0);
- ForceNl();
- }
- if (n_tmp_cset > 0) {
- prt_str("struct b_cset *r_cbuf;", 0);
- ForceNl();
- }
- /*
- * Indicate that buffers must be allocated by compiler and not
- * within the function.
- */
- il->u[5].n = n_tmp_str;
- il->u[6].n = n_tmp_cset;
- n_tmp_str = 0;
- n_tmp_cset = 0;
- }
-
- /*
- * Write declarations for result location and success continutation
- * parameters if they are needed.
- */
- if (rslt_loc) {
- prt_str("dptr r_rslt;", 0);
- ForceNl();
- }
- if (ret_flag & DoesSusp) {
- prt_str("continuation r_s_cont;", 0);
- ForceNl();
- }
-
- /*
- * Output the code for the function including ordinary declaration,
- * special declarations, and executable code.
- */
- prt_str("{", IndentInc);
- ForceNl();
- c_walk(dcls, IndentInc, 0);
- spcl_dcls(NULL);
- c_walk(stmts, IndentInc, 0);
- ForceNl();
- /*
- * If it is possible for excution to fall through to the end of
- * the body function, and it does so, return an A_FallThru signal.
- */
- if (fnc_ret == RetSig && fall_thru) {
- prt_str("return A_FallThru;", IndentInc);
- ForceNl();
- }
- prt_str("}\n", IndentInc);
- fclose(out_file);
- put_c_fl(cname, 1);
-
- /*
- * Restore the symbol table to its previous state.
- */
- for (var_ref = body_prms; var_ref != NULL; var_ref = var_ref->next) {
- var_ref->sym->id_type = var_ref->id_type;
- var_ref->sym->may_mod = 0;
- }
-
- return il;
- }
-
- /*
- * strct_typ - determine if the declaration may be for a structured type
- * and look for register declarations.
- */
- static int strct_typ(typ, is_reg)
- struct node *typ;
- int *is_reg;
- {
- if (typ->nd_id == LstNd) {
- return strct_typ(typ->u[0].child, is_reg) |
- strct_typ(typ->u[1].child, is_reg);
- }
- else if (typ->nd_id == PrimryNd) {
- switch (typ->tok->tok_id) {
- case Typedef:
- case Extern:
- errt2(typ->tok, "declare {...} should not contain ",
- typ->tok->image);
- case Register:
- *is_reg = 1;
- return 0;
- case TypeDefName:
- if (strcmp(typ->tok->image, "word") == 0 ||
- strcmp(typ->tok->image, "uword") == 0 ||
- strcmp(typ->tok->image, "dptr") == 0)
- return 0; /* assume non-structure type */
- else
- return 1; /* might be a structure (is not C_integer) */
- default:
- return 0;
- }
- }
- else {
- /*
- * struct, union, or enum.
- */
- return 1;
- }
- }
-
- /*
- * determine if the variable being declared evaluates to an address.
- */
- static int is_addr(dcltor, modifier)
- struct node *dcltor;
- int modifier;
- {
- switch (dcltor->nd_id) {
- case ConCatNd:
- /*
- * pointer?
- */
- if (dcltor->u[0].child != NULL)
- modifier = '*';
- return is_addr(dcltor->u[1].child, modifier);
- case PrimryNd:
- /*
- * We have reached the name.
- */
- switch (modifier) {
- case '\0':
- return 0;
- case '*':
- case '[':
- return 1;
- case ')':
- errt1(dcltor->tok,
- "declare {...} should not contain a prototype");
- }
- case PrefxNd:
- /*
- * (...)
- */
- return is_addr(dcltor->u[0].child, modifier);
- case BinryNd:
- /*
- * function or array.
- */
- return is_addr(dcltor->u[0].child, dcltor->tok->tok_id);
- }
- err1("rtt internal error detected in function is_addr()");
- /* NOTREACHED */
- }
-
- /*
- * chgn_ploc - if this is an "in-place" conversion to a C value, change
- * the "location" of the parameter being converted.
- */
- static novalue chng_ploc(cnv_typ, src)
- struct node *cnv_typ;
- struct node *src;
- {
- int loc;
-
- /*
- * Note, we know this is a valid conversion, because it got through
- * pass 1.
- */
- loc = PrmTend;
- if (cnv_typ->nd_id == PrimryNd)
- switch (cnv_typ->tok->tok_id) {
- case C_Integer:
- loc = PrmInt;
- break;
- case C_Double:
- loc = PrmDbl;
- break;
- case C_String:
- loc = PrmCStr;
- break;
- }
- else { /* must be exact conversion */
- if (cnv_typ->tok->tok_id == C_Integer)
- loc = PrmInt;
- }
- if (loc != PrmTend)
- src->u[0].sym->u.param_info.cur_loc = loc;
- }
-
- /*
- * cnt_bufs - See if we need to allocate a string or cset buffer for
- * this conversion.
- */
- static novalue cnt_bufs(cnv_typ)
- struct node *cnv_typ;
- {
- if (cnv_typ->nd_id == PrimryNd)
- switch (cnv_typ->tok->tok_id) {
- case Tmp_string:
- ++n_tmp_str;
- break;
- case Tmp_cset:
- ++n_tmp_cset;
- break;
- }
- }
-
- /*
- * mrg_abstr - merge (join) types of abstract returns on two execution paths.
- * The type lattice has three levels: NoAbstr is bottom, SomeType is top,
- * and individual types form the middle level.
- */
- static int mrg_abstr(sum, typ)
- int sum;
- int typ;
- {
- if (sum == NoAbstr)
- return typ;
- else if (typ == NoAbstr)
- return sum;
- else if (sum == typ)
- return sum;
- else
- return SomeType;
- }
- #endif /* Rttx */
-